import EventEmitter from 'events';
import type { CSSProperties } from 'react';
import SvgCanvas, { type BindListener, EventType } from '@svgedit/svgcanvas';
import defaultConfigs, { emptySvgStr } from './configs';
import shapes from './extensions/shapes';

type RemoveEventHandler = () => void;

class SvgEditor {
  public svgCanvas: SvgCanvas;
  private event = new EventEmitter();
  public inputElem: HTMLInputElement;
  public defaultConfigs = defaultConfigs;
  private removeEventHandlers: RemoveEventHandler[] = [];

  constructor(el: HTMLDivElement, defaultSvg?: string) {
    this.svgCanvas = new SvgCanvas(el, defaultConfigs);
    this.inputElem = this.createInputElement();
    this.setInputElem();
    this.loadExtensions();
    this.addRemoveEvents(this.addEvents());
    this.addRemoveEvents(this.addDelKeyEvent());
    this.setSvgString(defaultSvg ?? emptySvgStr);
  }

  // 添加移除事件的 hander
  private addRemoveEvents = (
    removeHandler: RemoveEventHandler
  ) => this.removeEventHandlers.push(removeHandler);

  // 执行移除事件
  private runRemoveEvents = () => {
    this.removeEventHandlers.forEach(fn => fn());
  }

  private addEvents = () => {
    const events: EventType[] = [
      'selected',
      'changed'
    ];
    for (const evtName of events) {
      this.svgCanvas.bind(evtName, (...arg) => {
        this.event.emit(evtName, ...arg);
      });
    }
    return () => {
      for (const evtName of events) {
        this.event.removeAllListeners(evtName);
      }
    }
  }

  private delKeyEventHandler = (evt: KeyboardEvent) => {
    const { key, target } = evt;
    const { tagName } = target as HTMLElement;
    if (key !== 'Backspace' || tagName === 'INPUT') {
      return;
    }
    evt.preventDefault();
    this.svgCanvas.deleteSelectedElements();
  }

  private addDelKeyEvent = () => {
    const eventName = 'keydown';
    const handler = this.delKeyEventHandler;
    document.addEventListener(eventName, handler);
    return () => document.removeEventListener(eventName, handler);
  }

  private loadExtensions = () => {
    this.svgCanvas.addExtension('shapes', () => {
      return shapes(this.svgCanvas);
    }, {});
  }

  private get textActions() {
    return this.svgCanvas.textActions;
  }

  private handleInput = () => {
    const txt = this.inputElem.value;
    this.setText(txt);
  }

  private createInputElement = () => {
    const input = document.createElement('input');
    input.addEventListener('input', this.handleInput);
    const style: CSSProperties = {
      opacity: 0,
      left: '-9999px',
      bottom: '-9999px',
      position: 'fixed'
    }
    for (const attr in style) {
      const key = attr as never;
      input.style[key] = style[key];
    }
    document.body.appendChild(input);
    return input;
  }

  private removeInputElement = () => {
    this.inputElem.removeEventListener('input', this.handleInput);
    document.body.removeChild(this.inputElem);
  }

  private setInputElem = () => {
    this.textActions.setInputElem(this.inputElem);
  }

  public setText = (text: string) => {
    this.svgCanvas.setTextContent(text);
    return this;
  }

  public bindEvent = (type: EventType, handler: BindListener) => {
    this.event.on(type, handler);
    const removeEvt = () => {
      this.event.off(type, handler);
    }
    return removeEvt;
  }

  public getMode = () => {
    return this.svgCanvas.getMode();
  }

  public setMode(mode: string) {
    this.svgCanvas.setMode(mode);
  }

  public textInputClear = () => {
    this.inputElem.value = '';
  }

  public setSvgString = (str: string) => {
    this.svgCanvas.setSvgString(str);
  }

  public destroy = () => {
    this.runRemoveEvents();
    this.removeInputElement();
  }
}

export default SvgEditor;